import axios from 'axios';
import Vue from "vue";
import store from '../vuex/store';

import {
  Message,
} from 'element-ui';
/**
 * 这段代码用于获取当前窗口的URL的根路径，即协议+主机名+端口号部分
 * window.location是一个JavaScript内置对象，用于获取当前窗口的URL信息。.origin是location对象的一个属性，用于获取当前URL的根路径
 */
let windowUrl = window.location.origin;

let apiBaseUrl = process.env.VUE_APP_API_BASE_PATH;
if (process.env.NODE_ENV === "production") {
  apiBaseUrl = windowUrl + apiBaseUrl;
}
//设置了请求拦截器，每次请求都会执行一次，可以在这里做一些公共的业务处理，比如请求头的统一设置，请求loading的显示等
//请求拦截器用于在发送请求之前执行一些操作，如设置请求头部的Token。
axios.interceptors.request.use(config => {
  const token = Vue.prototype.oauth2.getToken();
  // header 请求头设置token
  if (token) {
    config.headers.token = token;
  }
  return config
}, error => {
  return Promise.reject(error)
})

/*
 * 这段代码是使用axios的响应拦截器，用于在接收到响应后进行统一的错误处理和消息提示。
axios.interceptors.response.use用于注册响应拦截器，其中第一个参数是成功响应的处理函数，第二个参数是错误响应的处理函数
成功响应的处理函数是一个箭头函数，它直接返回接收到的响应结果res。
 */
axios.interceptors.response.use(res => {
  return res
},
  err => {
    // 在错误响应处理函数中，首先定义了一个变量msg，用于存储错误提示信息
    let msg = "";
    // 如果err.response不存在，表示出现了未知错误，将msg设为'未知错误'。
    if (!err.response) {
      msg = '未知错误'
    } else {
      //如果err.response.status等于401，表示登录失效，将msg设为'登录失效，请重新登录系统'。同时，使用setTimeout函数延迟一秒后
      //调用Vue.prototype.oauth2.toLogin()，执行重新登录的操作
      if (err.response.status == 401) {
        msg = "登录失效，请重新登录系统";
        setTimeout(() => {
          Vue.prototype.oauth2.toLogin();
        }, 1000);
      } else if (err.response.status == 403) {
        //如果err.response.status等于403，表示无权限进行该操作，将msg设为'无该操作权限，请联系管理员'
        msg = "无该操作权限，请联系管理员";
      } else {
        //如果以上条件都不满足，将msg设为'请求失败,错误码:' + err.response.status + ',
        //信息:' + (err.response.data && err.response.data.message ? err.response.data.message : "")
        msg = '请求失败,错误码:' + err.response.status + ",信息:" + (err.response.data && err.response.data.message ? err.response.data.message : "")
      }
    }
    // 使用Message函数从Element-UI库中展示一个错误提示消息，包含上述获取到的错误信息。
    Message({
      message: msg,
      type: 'error'
    });
    //调用store.commit("endLoading")来结束加载状态，可能是一个用于控制页面加载状态的Vuex操作
    store.commit("endLoading");
    //使用Promise.reject(err)返回一个被拒绝的Promise对象，将错误对象err作为拒绝的原因
    return Promise.reject(err);
  }
);

// 定义request方法，传入请求方式、请求地址、请求参数，返回一个Promise对象，成功返回res.data，失败返回err
const req = (method, url, params) => {
  store.commit("startLoading");
  return new Promise((resolve, reject) => {
    axios({
      method: method,
      url: apiBaseUrl + url,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      data: params,
      traditional: true,
      //transformRequest：请求数据的转换函数数组，其中定义了一个函数，用于将请求参数转换为URL编码的格式
      //在转换函数中，遍历请求参数对象，将每个键值对使用encodeURIComponent进行编码，并使用=和&拼接起来
      transformRequest: [
        function (data) {
          let ret = ''
          for (let it in data) { ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' }
          return ret
        }
      ]
      /*
      这部分代码是在axios请求成功后的处理逻辑，通过.then()方法链式调用
      当请求成功时，执行回调函数。
      在回调函数中，首先调用store.commit("endLoading")来结束加载状态，这可能是一个用于控制页面加载状态的Vuex操作。
      然后通过resolve(res.data)将返回的数据作为参数传递给resolve函数，以便在使用该函数时可以获取到请求成功的数据
      这段代码的作用是在请求成功时执行一些操作，结束加载状态，并将返回的数据传递给Promise的resolve函数，以便后续处理成功的结果
      需要注意的是，该代码中使用了store.commit方法来提交一个Vuex的mutation，以改变应用状态。
      前面开始的时候，有个store.commit("startLoading");，结尾处有个store.commit("endLoading");，这两个方法都是用来改变应用状态的。
      */
    }).then(res => {
      store.commit("endLoading");
      resolve(res.data);
    })
      .catch(err => {
        store.commit("endLoading");
        reject(err)
      })
  });
};

// 定义json方法，传入请求方式、请求地址、请求参数，返回一个Promise对象，成功返回res.data，失败返回err
// req函数使用了application/x-www-form-urlencoded作为请求头部的Content-Type，而json函数使用了application/json
const json = (method, url, params) => {
  return new Promise((resolve, reject) => {
    axios({
      method: method,
      url: apiBaseUrl + url,
      headers: {
        'Content-Type': 'application/json'
      },
      data: params,
      traditional: true,
    }).then(res => {
      resolve(res.data);
    })
      .catch(err => {
        reject(err)
      })
  });
};

//通过export关键字，将req和json函数导出，以便其他模块可以导入并使用
export {
  req,
  json
}
